﻿using Furion.DatabaseAccessor;
using Furion.DatabaseAccessor.Extensions;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using LimaLims.Application.Service.Cache;
using LimaLims.Application.Service.Tenant.Dto;
using LimaLims.Core;
using LimaLims.Core.Entity.System;
using LimaLims.Core.Enum;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Yitter.IdGenerator;

namespace LimaLims.Application.Service.Tenant
{
    /// <summary>
    /// 租户
    /// </summary>
    [Route("api")]
    public class SysTenantService : IDynamicApiController, ITransient
    {
        private readonly IRepository<SysTenant> _sysTenantRep;  // 租户表仓储
        private readonly IRepository<SysUser> _sysUserRep;
        private readonly IRepository<SysRole> _sysRoleRep;  // 角色表仓储
        private readonly IRepository<SysUserRole> _sysUserRoleRep;  // 用户角色表仓储
        private readonly IRepository<SysRoleMenu> _sysRoleMenuRep;// 角色菜单表仓储
        private readonly IRepository<SysFileGroup> _sysFileGroupRep;
        private readonly ISysCacheService _sysCacheService;

        public SysTenantService(IRepository<SysTenant> sysTenantRepository, IRepository<SysUser> sysUserRep, IRepository<SysRole> sysRoleRep, IRepository<SysUserRole> sysUserRoleRep,  IRepository<SysFileGroup> sysFileGroupRep, IRepository<SysRoleMenu> sysRoleMenuRep, ISysCacheService sysCacheService)
        {
            _sysTenantRep = sysTenantRepository;
            _sysUserRep = sysUserRep;
            _sysRoleRep = sysRoleRep;
            _sysUserRoleRep = sysUserRoleRep;
            _sysFileGroupRep = sysFileGroupRep;
            _sysRoleMenuRep = sysRoleMenuRep;
            _sysCacheService = sysCacheService;
        }

        /// <summary>
        /// 新增租户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("sysTenant/add")]
        [UnitOfWork]
        public async Task Add(AddTenantInput input)
        {
            var isNameExist = await _sysTenantRep.DetachedEntities.AnyAsync(u => u.Name == input.Name);
            if (isNameExist)
                throw Oops.Oh("已存在同名租户");

            var isAdminExist = await _sysTenantRep.DetachedEntities.AnyAsync(u => u.AdminName == input.AdminName);
            if (isAdminExist)
                throw Oops.Oh("已存在同名的租户管理员");

            await CreateTenant(input);
        }

        /// <summary>
        /// 创建租户基本信息以及对应的表数据
        /// </summary>
        [NonAction]
        public async Task CreateTenant(AddTenantInput input)
        {
            var tenant = input.Adapt<SysTenant>();
            tenant.Id = YitIdHelper.NextId();
            tenant.CreatedTime = DateTime.Now;
            tenant.CreatedUserName = CurrentUserInfo.Account;

            await tenant.InsertNowAsync();

            var newUser = new SysUser
            {
                TenantId = tenant.Id,
                Account = tenant.AdminName,
                Name = input.UserName,
                Password = MD5Encryption.Encrypt(CommonConst.DEFAULT_PASSWORD),
                Email = tenant.Email,
                Phone = tenant.Phone,
                AdminType = AdminType.Admin
            };

            if (string.IsNullOrWhiteSpace(newUser.Name))
            {
                newUser.Name= tenant.AdminName;
            }
            await _sysUserRep.InsertNowAsync(newUser);

            //新增租户素材默认分组
            var fileGroup = new SysFileGroup
            {
                Title = "默认分组",
                TenantId = tenant.Id
            };
            await _sysFileGroupRep.InsertNowAsync(fileGroup);

            // 初始化角色
            var newRole = new SysRole
            {
                TenantId = tenant.Id,
                Name = "租管-" + tenant.Name,
                Code = CommonConst.SysAdminRole,
                Remark = $"{tenant.Name}系统默认角色"
            };
            await _sysRoleRep.InsertNowAsync(newRole);

            // 关联用户及角色
            var newUserRole = new SysUserRole
            {
                SysRoleId = newRole.Id,
                SysUserId = newUser.Id
            };
            await _sysUserRoleRep.InsertNowAsync(newUserRole);

        }

        /// <summary>
        /// 更新租户默认角色菜单权限
        /// </summary>
        /// <param name="menuIdList"></param>
        /// <param name="roleId"></param>
        /// <returns></returns>
        private async Task UpdateTenantRoleMenu(List<long> menuIdList, long roleId)
        {
            if (menuIdList == null || menuIdList.Count < 1)
                return;

            var roleMenus = await _sysRoleMenuRep.DetachedEntities.Where(u => u.SysRoleId == roleId).ToListAsync();

            await _sysRoleMenuRep.DeleteAsync(roleMenus);

            var menus = menuIdList.Select(u => new SysRoleMenu
            {
                SysRoleId = roleId,
                SysMenuId = u
            }).ToList();

            await _sysRoleMenuRep.InsertAsync(menus);

            // 清除缓存
            await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_MENU);
            await _sysCacheService.DelByPatternAsync(CommonConst.CACHE_KEY_PERMISSION);

        }


        /// <summary>
        /// 获取租户分页列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("sysTenant/page")]
        public async Task<PageResult<TenantOutput>> QueryPage([FromQuery] PageTenantInput input)
        {
            var name = !string.IsNullOrEmpty(input.SearchValue?.Trim());

            var tenants = await _sysTenantRep.DetachedEntities
                .Where((name, u => EF.Functions.Like(u.Name, $"%{input.SearchValue.Trim()}%")))
                .Where(s => s.Id != 142307070918780)
                                        .OrderBy(u => u.Sort)
                                         .Select(a => new TenantOutput
                                         {
                                             Id = a.Id,
                                             Name = a.Name,
                                             AdminName = a.AdminName,
                                             Phone = a.Phone,
                                             Email = a.Email,
                                             ValidStatus = a.ValidStatus,
                                             CreatedTime = a.CreatedTime
                                         }).ToADPagedListAsync(input.PageNo, input.PageSize);

            return tenants;
        }
        /// <summary>
        /// 获取租户
        /// </summary>
        /// <param name="tenantId"></param>
        /// <returns></returns>
        [HttpGet("sysTenant/detail")]
        public async Task<TenantOutput> GetDetail(long tenantId)
        {
            var sysTenant = await _sysTenantRep.DetachedEntities.FirstOrDefaultAsync(u => u.Id == tenantId);

            var sysUser = await GetTenantAdminUser(tenantId);


            var sysTenantInfo = new TenantOutput
            {
                Id = sysTenant.Id,
                UserId = sysUser.Id,
                Name = sysTenant.Name,
                AdminName = sysTenant.AdminName,
                UserName = sysUser.Name,
                Phone = sysTenant.Phone,
                Email = sysTenant.Email,
                Remark = sysTenant.Remark,
                ValidStatus = sysTenant.ValidStatus,
            };
            return sysTenantInfo;
        }


        /// <summary>
        /// 删除租户
        /// </summary>
        /// <param name="tenantId"></param>
        /// <returns></returns>
        [HttpPost("sysTenant/delete")]
        [UnitOfWork]
        public async Task Delete(long tenantId)
        {
            var sysTenant = await _sysTenantRep.FirstOrDefaultAsync(u => u.Id == tenantId);
            if (sysTenant == null)
                throw Oops.Oh("不存在此数据");

            await sysTenant.DeleteAsync();
        }
        /// <summary>
        /// 获取租户管理员用户
        /// </summary>
        /// <param name="tenantId"></param>
        /// <returns></returns>
        private async Task<SysUser> GetTenantAdminUser(long tenantId)
        {
            return await _sysUserRep.Where(u => u.TenantId == tenantId, false, true)
                                    .Where(u => u.AdminType == AdminType.Admin).FirstOrDefaultAsync();
        }

        /// <summary>
        /// 更新租户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("sysTenant/edit")]
        [UnitOfWork]
        public async Task UpdateTenant(UpdateTenantInput input)
        {
            var isExist = await _sysTenantRep.AnyAsync(u => u.Name == input.Name && u.Id != input.Id);
            if (isExist)
                throw Oops.Oh("已存在同名租户");

            isExist = await _sysUserRep.AnyAsync(u => u.Account == input.AdminName && u.Id != input.UserId);
            if (isExist)
                throw Oops.Oh("已存在同名的租户管理员");

            var tenant = input.Adapt<SysTenant>();
            tenant.UpdatedTime = DateTime.Now;
            tenant.UpdatedUserName = CurrentUserInfo.Account;
            tenant.UpdatedUserId = CurrentUserInfo.UserId;
            await _sysTenantRep.UpdateAsync(tenant, true);

            // 更新系统用户
            var sysUser = await GetTenantAdminUser(input.Id);

            sysUser.Account = input.AdminName;
            sysUser.Name = input.UserName;
            sysUser.UpdatedTime = DateTime.Now;
            sysUser.UpdatedUserName = CurrentUserInfo.Account;
            sysUser.UpdatedUserId = CurrentUserInfo.UserId;

            await _sysUserRep.UpdateAsync(sysUser, true);

        }
    }
}
